#include "WHT20_I2C.h"

/*******************设备状态***********************/
WHT20::WHT20(const uint8_t deviceAddress)
{
    _deviceAddress = deviceAddress;
}


//将设备连接到I2C总线，完成读取温湿度之前的工作（校准检验）
//连接正常，状态字的校准使能位bit3为1（校准检验正常），则返回1，否则返回0
bool WHT20::begin()
{
    if (isConnected() == false)
        return false;

    // Wait 40 ms after power-on before reading temp or humidity. Datasheet pg 8
    delay(40);

    // 检查状态字的校准使能位（calibrated bit）是否为1，如果不为1，要发送0XBE命令初始化传感器
    if (isCalibrated() == false)
    {
        // 状态字的校准使能位不为1后的初始化操作，初始化成功返回1，Send 0xBE0800
        initialize();
        //触发测量，命令为0xAC，命令参数为0x33，0x00，触发成功返回1，否则返回0 Send 0xAC3300
        triggerMeasurement();
        //等待75ms待测量完成
        delay(75); 
        //下面是防止程序卡死的机制（WHT20一直处于测量中）
        uint8_t counter = 0;
        //isBusy：返回状态字的忙状态标志位bit7，不忙返回0，表示WHT20已经测量完成
        while (isBusy())
        {
            delay(1);
            if (counter++ > 100)
                return (false); //等待100ms后放弃测量，退出该函数
        }
        // This calibration sequence is not completely proven. It's not clear how and when the cal bit clears
        // This seems to work but it's not easily testable
        if (isCalibrated() == false)
        {
            return (false);
        }
    }
    //再次检查状态字的校准使能位（calibrated bit）是否为1
    if (isCalibrated() == false)
        return false;
    // Mark all datums as fresh (not read before)
    //标记温度和湿度可以被修改（被新值覆盖）
    sensorQueried.temperature = true;
    sensorQueried.humidity = true;

    return true;
}

//检测WHT20是否连接到了I2C总线
//正确连接返回：true
//连接失败返回false
bool WHT20::isConnected()
{
    Wire.beginTransmission(_deviceAddress);
    if (Wire.endTransmission() == 0)
        return true;

    // If IC failed to respond, give it 20ms more for Power On Startup
    // Datasheet pg 7
    delay(20);

    Wire.beginTransmission(_deviceAddress);
    if (Wire.endTransmission() == 0)
        return true;

    return false;
}


/******************测量帮助函数*********************/
//获得显示WHT20状态的一个字节，返回的是WHT20接到命令后给的状态字
uint8_t WHT20::getStatus()
{
    Wire.requestFrom(_deviceAddress, (uint8_t)1);
    if (Wire.available())
        return (Wire.read());
    return (0);
}

//检查状态字的校准使能位（calibrated bit）
//返回状态字的校准使能位bit[3]
bool WHT20::isCalibrated()
{
    return (getStatus() & (1 << 3));
}

// Returns the state of the busy bit in the status byte
//返回状态字的忙状态标志位bit7，在忙返回0，WHT20已经测量完成返回1
bool WHT20::isBusy()
{
    return (getStatus() & (1 << 7));
}

//状态字的校准使能位不为1后的初始化操作，初始化成功返回1
bool WHT20::initialize()
{
    Wire.beginTransmission(_deviceAddress);
    Wire.write(WHT20_reg_initialize_command);
    Wire.write((uint8_t)0x08);
    Wire.write((uint8_t)0x00);
    if (Wire.endTransmission() == 0)
        return true;
    return false;
}

//触发WHT20进行测量，命令为0xAC，命令参数为0x33，0x00
//触发成功返回1，否则返回0
bool WHT20::triggerMeasurement()
{
    Wire.beginTransmission(_deviceAddress);
    Wire.write(WHT20_reg_measure_trigger_command);
    Wire.write((uint8_t)0x33);
    Wire.write((uint8_t)0x00);
    if (Wire.endTransmission() == 0)
        return true;
    return false;
}


/********************上面是测量前的准备工作，现在开始为获取温湿度数据做准备**************/
// 读取6个字节的数据，丢弃第一个字节的状态字，将剩下的5个字节的数据分别赋值给温度湿度data
void WHT20::readData()
{
    // Clear previous data
    //清除寄存器原来的关于温湿度的数据，每次进行覆盖
    sensorData.temperature = 0;
    sensorData.humidity = 0;

    if (Wire.requestFrom(_deviceAddress, (uint8_t)6) > 0)
    {
        Wire.read(); // Read and discard state(接收一个自己的数据不使用，作用：丢弃状态字节的数据)

        //获取湿度的数据，两个半字节，共20位
        uint32_t incoming = 0;
        incoming |= (uint32_t)Wire.read() << (8 * 2);
        incoming |= (uint32_t)Wire.read() << (8 * 1);
        uint8_t midByte = Wire.read();

        incoming |= midByte;
        sensorData.humidity = incoming >> 4;

        //获取温度的数据，两个半字节，共20位 
        sensorData.temperature = (uint32_t)midByte << (8 * 2);
        sensorData.temperature |= (uint32_t)Wire.read() << (8 * 1);
        sensorData.temperature |= (uint32_t)Wire.read() << (8 * 0);

        // Need to get rid of data in bits > 20（温度数据为20位）
        sensorData.temperature = sensorData.temperature & ~(0xFFF00000);

        //将数据标记为已经被读取，不可以再次读取
        sensorQueried.temperature = false;
        sensorQueried.humidity = false;
    }
}

// Triggers a measurement if one has not been previously started, then returns false
// If measurement has been started, checks to see if complete.
// If not complete, returns false
// If complete, readData(), mark measurement as not started, return true
//判断是否有新数据可用，如果有，则返回1
bool WHT20::available()
{
    //measurementStarted在h文件中有定义，定义是false
    if (measurementStarted == false)
    {
        triggerMeasurement();
        measurementStarted = true;
        return (false);
    }
    //触发测量后检查，返回状态字的忙状态标志位bit7，在忙返回0，WHT20已经测量完成返回1
    if (isBusy() == true)
    {
        return (false);
    }

    readData();
    measurementStarted = false;
    return (true);
}

//软件复位WHT20传感器
bool WHT20::softReset()
{
    Wire.beginTransmission(_deviceAddress);
    Wire.write(sfe_WHT20_reg_reset);
    if (Wire.endTransmission() == 0)
        return true;
    return false;
}

/**********************************开始测量*****************************************/
float WHT20::getTemperature()
{
    if (sensorQueried.temperature == true)   //先检查是否可以被读取
    {
        // We've got old data so trigger new measurement
        //触发WHT20进行测量，命令为0xAC，命令参数为0x33，0x00
        //触发成功返回1，否则返回0
        triggerMeasurement();

        delay(75); // Wait for measurement to complete

        uint8_t counter = 0;
        while (isBusy())
        {
            delay(1);
            if (counter++ > 100)
                return (false); // Give up after 100ms
        }

        readData();
    }

    // From datasheet pg 8
    float tempCelsius = ((float)sensorData.temperature / 1048576) * 200 - 50;

    // Mark data as old
    sensorQueried.temperature = true;

    return tempCelsius;
}

float WHT20::getHumidity()
{
    if (sensorQueried.humidity == true)
    {
        // We've got old data so trigger new measurement
        triggerMeasurement();

        delay(75); // Wait for measurement to complete

        uint8_t counter = 0;
        while (isBusy())
        {
            delay(1);
            if (counter++ > 100)
                return (false); // Give up after 100ms
        }

        readData();
    }

    // From datasheet pg 8
    float relHumidity = ((float)sensorData.humidity / 1048576) * 100;

    // Mark data as old
    sensorQueried.humidity = true;

    return relHumidity;
}






